﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
using Npgsql;
using System.IO;
using System.Diagnostics;

namespace Koala
{
    public partial class MainForm : Form
    {
        private List<NodeTree> _nodeList;

        public MainForm()
        {
            InitializeComponent();
            _nodeList = new List<NodeTree>();
            //for restoring windowa state. Write out metrics(geometry) while windows exist
            GeometryFromString(Properties.Settings.Default.WindowsGeometry, this);

            TreeExplorer.Nodes[0].ContextMenuStrip = contextMenuStrip;
        }

        private void OnConnectToHost(object sender, EventArgs e)
        {
            ConnectionForm frmConnect = new ConnectionForm();
            frmConnect.ShowDialog();

            if (frmConnect.Success)
            {
                frmConnect.GetNode().ImageIndex = 1;
                frmConnect.GetNode().SelectedImageIndex = 1;

                frmConnect.GetNode().ContextMenuStrip = contextMenuStrip1;

                TreeExplorer.Nodes[0].Nodes.Add(frmConnect.GetNode());
                TreeExplorer.Nodes[0].ExpandAll();
                TreeExplorer.SelectedNode = frmConnect.GetNode();

                _nodeList.Add(frmConnect.GetNode());

                Refresh(TreeExplorer.SelectedNode);
            }
        }

        private void OnDisConnectFromHost(object sender, EventArgs e)
        {
            if (TreeExplorer.SelectedNode != TreeExplorer.Nodes[0])
            {
                NodeTree NODE = _nodeList.Find(item => item.Connection.Host + ":" 
                                                + item.Connection.Port.ToString() == TreeExplorer.SelectedNode.Text);

                NODE.Disconnect();
                _nodeList.RemoveAt(_nodeList.IndexOf(NODE));

                TreeExplorer.SelectedNode.Remove();
            }
        }

        private void Refresh(TreeNode node)
        {
            int selected=0;

            DataSet ds = new DataSet();
            DataTable dt = new DataTable();

            NodeTree NODE = _nodeList.Find(item => (item.Connection.Host + ":" +
                                                    item.Connection.Port.ToString()) == node.Text);
            NpgsqlDataAdapter da = new NpgsqlDataAdapter("select datname as DB, numbackends as Connection_Count from pg_stat_database where datname not in ('postgres', 'template0', 'template1')", NODE.Connection);

            if (!timer.Enabled)
                if (resGrid.SelectedRows.Count > 0)
                    selected = resGrid.SelectedRows[0].Index;

            ds.Reset();
            da.Fill(ds);

            dt = ds.Tables[0];

            dt.Columns[0].Caption = "Database";
            dt.Columns[1].Caption = "Connection Count";

            resGrid.DataSource = dt;
            resGrid.Columns[0].HeaderText = "Database";
            resGrid.Columns[1].HeaderText = "Connection Count";

            if (!timer.Enabled)
                resGrid.Rows[selected].Selected = true;
        }

        private void RefreshData(object sender, EventArgs e)
        {
            if (TreeExplorer.SelectedNode != TreeExplorer.Nodes[0])
            {
                if (TreeExplorer.Nodes[0].GetNodeCount(true) != 0)
                {
                    Refresh(TreeExplorer.SelectedNode);
                }
            }
        }


        #region restoring position and windows state

        public static void GeometryFromString(string thisWindowsGeometry,Form formIn)
        {
            if (string.IsNullOrEmpty(thisWindowsGeometry) == true)
            {
                return;
            }
            string[] numbers = thisWindowsGeometry.Split('|');
            string windowString = numbers[4];
            if (windowString == "Normal")
            {
                Point windowPoint = new Point(int.Parse(numbers[0]),
                    int.Parse(numbers[1]));
                Size windowSize = new Size(int.Parse(numbers[2]),
                    int.Parse(numbers[3]));

                bool locOkay = GeometryIsBizarreLocation(windowPoint, windowSize);
                bool sizeOkay = GeometryIsBizarreSize(windowSize);

                if (locOkay == true && sizeOkay == true)
                {
                    formIn.Location = windowPoint;
                    formIn.Size = windowSize;
                    formIn.StartPosition = FormStartPosition.Manual;
                    formIn.WindowState = FormWindowState.Normal;
                }
                else if (sizeOkay == true)
                {
                    formIn.Size = windowSize;
                }
            }
            else if (windowString == "Maximized")
            {
                formIn.Location = new Point(100, 100);
                formIn.StartPosition = FormStartPosition.Manual;
                formIn.WindowState = FormWindowState.Maximized;
            }
        }


        //if the location (top and left corner point) of the window is okay to restore

        private static bool GeometryIsBizarreLocation(Point loc, Size size)
        {
            bool locOkay;
            if (loc.X < 0 || loc.Y < 0)
            {
                locOkay = false;
            }
            else if (loc.X + size.Width > Screen.PrimaryScreen.WorkingArea.Width)
            {
                locOkay = false;
            }
            else if (loc.Y + size.Height > Screen.PrimaryScreen.WorkingArea.Height)
            {
                locOkay = false;
            }
            else
            {
                locOkay = true;
            }
            return locOkay;
        }

        //Basically, the size is okay whenever it is smaller than the screen. If the window is positioned partly off-screen,
        //but it is small enough to fit on the screen, it is simply relocated, and the size doesn't change.

        private static bool GeometryIsBizarreSize(Size size)
        {
            return (size.Height <= Screen.PrimaryScreen.WorkingArea.Height &&
                size.Width <= Screen.PrimaryScreen.WorkingArea.Width);
        }

        //serialize or persist a "geometry" string
        public static string GeometryToString(Form mainForm)
        {
            return mainForm.Location.X.ToString() + "|" +
                mainForm.Location.Y.ToString() + "|" +
                mainForm.Size.Width.ToString() + "|" +
                mainForm.Size.Height.ToString() + "|" +
                mainForm.WindowState.ToString();
        }
        #endregion

        

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            Properties.Settings.Default.WindowsGeometry = GeometryToString(this);
            Properties.Settings.Default.Save();
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            if (rCompress.Checked)
                saveFileDialog.Filter = "Custom(*.dump)|*.dump";
            if (rTar.Checked)
                saveFileDialog.Filter = "TAR (*.tar)|*.tar";
            if (rPlain.Checked)
                saveFileDialog.Filter = "Plain Text(*.sql)|*.sql";

            saveFileDialog.ShowDialog();
            txtDPath.Text = saveFileDialog.FileName;
        }

        private void btnSelect_Click(object sender, EventArgs e)
        {
            openFileDialog.ShowDialog();
            txtRPath.Text = openFileDialog.FileName;
        }

        private void OnCreateDump(object sender, EventArgs e)
        {
            string _args = "";

            if (File.Exists(txtDPath.Text))
                if (MessageBox.Show("File already exist. Do you want to replace them?",
                                    "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) ==
                                    DialogResult.No) { return; }

            if (rCompress.Checked) _args += " -Fc";
            if (rTar.Checked) _args += " -Ft";
            if (rPlain.Checked) _args += " -Fp";
            if (cbxDataOnly.Checked) _args += " -a";
            if (cbxBlobs.Checked) _args += " -b";
            if (cbxOids.Checked) _args += " -o";
            if (cbxCreateDB.Checked) _args += " -C";
            if (cbxDeleteObj.Checked) _args += " -c";

            _args += " -h " + (TreeExplorer.SelectedNode as NodeTree).Connection.Host;
            _args += " -p " + (TreeExplorer.SelectedNode as NodeTree).Connection.Port.ToString();
            _args += " -U " + (TreeExplorer.SelectedNode as NodeTree).UserName;
            _args += " " + resGrid[0, resGrid.SelectedRows[0].Index].Value.ToString() + " > \"" + txtDPath.Text + "\"";

            CreateDump(_args,
                        (TreeExplorer.SelectedNode as NodeTree).UserName,
                            (TreeExplorer.SelectedNode as NodeTree).Password);            
        }

        private void CreateDump(string args, string user, string pass)
        {
            TextWriter tw = new StreamWriter("dump.cmd");
            tw.WriteLine("SET PGUSER="+user);
            tw.WriteLine("SET PGPASSWORD=" + pass);
            tw.WriteLine(@"""C:\Program Files\PostgreSQL\9.0\bin\pg_dump.exe"" " + args);
            tw.Close();

            Process proc = new Process();

            proc.EnableRaisingEvents = false;
            proc.StartInfo.UseShellExecute = false;
            proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
            proc.StartInfo.CreateNoWindow = true;
            proc.StartInfo.FileName = "dump.cmd";
            
            proc.Start();
            proc.WaitForExit();

            MessageBox.Show("Dump wa created! Path to file \n" + txtDPath.Text, "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        private void OnRestoreDump(object sender, EventArgs e)
        {
            string _args = "";
            string _args_drop = "";
            
            if (checkBox3.Checked) _args += " -a";
            if (checkBox2.Checked) _args += " -c";
            if (checkBox1.Checked) _args += " -C";

            _args += " -h " + (TreeExplorer.SelectedNode as NodeTree).Connection.Host;
            _args += " -p " + (TreeExplorer.SelectedNode as NodeTree).Connection.Port.ToString();
            _args += " -U " + (TreeExplorer.SelectedNode as NodeTree).UserName;
            _args += " -d " + resGrid[0, resGrid.SelectedRows[0].Index].Value.ToString() + " \"" + txtRPath.Text + "\"";

            _args_drop += " -h " + (TreeExplorer.SelectedNode as NodeTree).Connection.Host;
            _args_drop += " -p " + (TreeExplorer.SelectedNode as NodeTree).Connection.Port.ToString();
            _args_drop += " -U " + (TreeExplorer.SelectedNode as NodeTree).UserName;
            _args_drop += " " + resGrid[0, resGrid.SelectedRows[0].Index].Value.ToString();

            RestoreDump(_args, _args_drop,
                        (TreeExplorer.SelectedNode as NodeTree).UserName,
                            (TreeExplorer.SelectedNode as NodeTree).Password);           
        }

        private void RestoreDump(string args, string args_drop, string user, string pass)
        {
            TextWriter tw = new StreamWriter("dump.cmd");
            tw.WriteLine("SET PGUSER=" + user);
            tw.WriteLine("SET PGPASSWORD=" + pass);
            tw.WriteLine(@"start """" /wait ""C:\Program Files\PostgreSQL\9.0\bin\dropdb.exe"" " + args_drop);
            tw.WriteLine(@"start """" /wait ""C:\Program Files\PostgreSQL\9.0\bin\createdb.exe"" " + args_drop);
            tw.WriteLine(@"start """" /wait ""C:\Program Files\PostgreSQL\9.0\bin\pg_restore.exe"" " + args);
            tw.Close();

            Process proc = new Process();

            proc.EnableRaisingEvents = false;
            proc.StartInfo.UseShellExecute = false;
            proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
            proc.StartInfo.CreateNoWindow = true;
            proc.StartInfo.FileName = "dump.cmd";

            proc.Start();
            proc.WaitForExit();

            MessageBox.Show("Restore completed!", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        private void cbxDeleteObj_CheckedChanged(object sender, EventArgs e)
        {
            if (cbxDeleteObj.Checked)
                cbxCreateDB.Enabled = false;
            else
                cbxCreateDB.Enabled = true;
        }

        private void cbxCreateDB_CheckedChanged(object sender, EventArgs e)
        {
            if (cbxCreateDB.Checked)
                cbxDeleteObj.Enabled = false;
            else
                cbxDeleteObj.Enabled = true;
        }

        private void tbtnStartStop_Click(object sender, EventArgs e)
        {
            timer.Enabled = !timer.Enabled;

            if (timer.Enabled)
            {
                tbtnStartStop.Image = Koala.Properties.Resources.button_pause;
                tbtnStartStop.Text = "Stop refreshing";
                btnRefresh.Enabled = false;
                
            }
            else
            {
                tbtnStartStop.Image = Koala.Properties.Resources.start_1;
                tbtnStartStop.Text = "Start refreshing";
                btnRefresh.Enabled = true;
            }
        }

    }
}
